/*
//
//              INTEL CORPORATION PROPRIETARY INFORMATION
//  This software is supplied under the terms of a license  agreement or
//  nondisclosure agreement with Intel Corporation and may not be copied
//  or disclosed except in  accordance  with the terms of that agreement.
//    Copyright (c) 2007 Intel Corporation. All Rights Reserved.
//
//
*/

#include "umc_defs.h"
#if defined(UMC_ENABLE_AVS_VIDEO_DECODER)

#include "umc_avs_dec.h"
#include "umc_avs_dec_fusion_core.h"
#include "umc_avs_thread.h"

#include "vm_sys_info.h"
#include "umc_event.h"

namespace UMC
{

enum
{
    AVS_DEC_MAX_NUM_THREADS     = 8
};

AVSVideoDecoder::AVSVideoDecoder(void)
{
    m_pCore = NULL;
    m_pThreads = NULL;
    m_numThreads = 0;

} // AVSVideoDecoder::AVSVideoDecoder(void)

AVSVideoDecoder::~AVSVideoDecoder(void)
{
    // close the object
    Close();

} // AVSVideoDecoder::AVSVideoDecoder(void)

Status AVSVideoDecoder::Close(void)
{
    // terminate working threads
    if (m_pThreads)
        delete [] m_pThreads;

    // close fusion core
    if (m_pCore)
        delete m_pCore;

    m_pCore = NULL;
    m_pThreads = NULL;
    m_numThreads = 0;

    // call the parent's method
    VideoDecoder::Close();

    return UMC_OK;

} // Status AVSVideoDecoder::Close(void)

Status AVSVideoDecoder::Init(BaseCodecParams *pInit)
{
    VideoDecoderParams *pParams = DynamicCast<VideoDecoderParams> (pInit);
    Status umcRes;
    Ipp32u i, iThreads;

    // check error(s)
    if (NULL == pParams)
        return UMC_ERR_NULL_PTR;

    // release the object before initialization
    Close();

    // call the parent's method
    umcRes = VideoDecoder::Init(pParams);
    if (UMC_OK != umcRes)
        return umcRes;

    // calculate number of threads
    if (pParams->numThreads)
        iThreads = IPP_MIN(pParams->numThreads, AVS_DEC_MAX_NUM_THREADS);
    else
        iThreads = vm_sys_info_get_cpu_num();

    // create a fusion core
    m_pCore = new AVSDecFusionCore();
    if (NULL == m_pCore)
        return UMC_ERR_ALLOC;
    // initialize the fusion core
    umcRes = m_pCore->Init(iThreads, pParams);
    if (UMC_OK != umcRes)
        return UMC_ERR_INIT;

    // allocate an array of thread objects
    m_pThreads = new AVSThread[iThreads];
    if (NULL == m_pThreads)
        return UMC_ERR_ALLOC;
    // initialize the threads
    for (i = 0; i < iThreads; i += 1)
    {
        umcRes = m_pThreads[i].Init(m_pCore, i);
        if (UMC_OK != umcRes)
            return UMC_ERR_INIT;
    }

    return UMC_OK;

} // Status AVSVideoDecoder::Init(BaseCodecParams *pInit)

Status AVSVideoDecoder::GetFrame(MediaData *pSrc, MediaData *pDst)
{
    VideoData *pVideoDst = DynamicCast<VideoData> (pDst);
    Status umcRes;

    // check error(s)
    if (NULL == pVideoDst)
        return UMC_ERR_NULL_PTR;
    if (NULL == m_pCore)
        return UMC_ERR_NOT_INITIALIZED;

    // try to load source to the core
    umcRes = m_pCore->LoadSource(pSrc);
    if (UMC_OK != umcRes)
        return umcRes;

    // set the destination video plane(s)
    umcRes = m_pCore->SetDestination(pVideoDst);
    if (UMC_OK != umcRes)
        return umcRes;

    // take a part in decoding process
    m_pThreads[0].DoJob();

    return UMC_OK;

} // Status AVSVideoDecoder::GetFrame(MediaData *pSrc, MediaData *pDst)

Status AVSVideoDecoder::GetInfo(BaseCodecParams * /*pCodecParams*/)
{
    return UMC_ERR_NOT_IMPLEMENTED;

} // Status AVSVideoDecoder::GetInfo(BaseCodecParams *pCodecParams)

Status AVSVideoDecoder::Reset(void)
{
    Event done;
    Ipp32u i;

    // initialize the event
    done.Init(0, 0);

    // make all thread sleep
    for (i = 1; i < m_numThreads; i += 1)
        m_pThreads[i].GoSleep(done);

    // reset the fusion core
    m_pCore->Reset();

    // wake up all threads
    for (i = 1; i < m_numThreads; i += 1)
        m_pThreads[i].WakeUp(done);

    return UMC_OK;

} // Status AVSVideoDecoder::Reset(void)

Status AVSVideoDecoder::ResetSkipCount(void)
{
    return UMC_ERR_NOT_IMPLEMENTED;

} // Status AVSVideoDecoder::ResetSkipCount(void)

Status AVSVideoDecoder::SkipVideoFrame(Ipp32s)
{
    return UMC_ERR_NOT_IMPLEMENTED;

} // Status AVSVideoDecoder::SkipVideoFrame(Ipp32s)

Ipp32u AVSVideoDecoder::GetNumOfSkippedFrames(void)
{
    return 0;

} // Ipp32u AVSVideoDecoder::GetNumOfSkippedFrames(void)

} // namespace UMC

#endif // defined(UMC_ENABLE_AVS_VIDEO_DECODER)
